package ar.com.seminario.service;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.List;
import java.util.Vector;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import ar.com.seminario.common.persistence.exception.DaoException;
import ar.com.seminario.common.service.definition.BaseService;
import ar.com.seminario.common.service.exception.ServiceException;
import ar.com.seminario.common.util.ConexiaDateUtil;
import ar.com.seminario.dao.SolicitudIngresoDao;
import ar.com.seminario.dto.EntrevistaDto;
import ar.com.seminario.dto.SolicitudIngresoDto;
import ar.com.seminario.model.Entrevista;
import ar.com.seminario.model.Oficina;
import ar.com.seminario.model.Perfil;
import ar.com.seminario.model.SolicitudIngreso;
import ar.com.seminario.model.enumerados.EstadoSolicitud;
import ar.com.seminario.model.enumerados.NecesidadIngreso;
import ar.com.seminario.systema.model.TipoUsuario;

/**
 * Servicio de acceso a las solicitudes del sistema de RRHH.
 * 
 * @author Dario Camarro
 */
@Service
@Transactional
public class SolicitudIngresoService extends BaseService implements ISolicitudIngresoService {

	/**
	 * Servicio de acceso a {@link Perfil}.
	 */
	@Autowired
	private IPerfilService perfilService;

	/**
	 * Servicio de acceso a {@link Entrevista}.
	 */
	@Autowired
	private IEntrevistaService entrevistaService;

	/**
	 * Servicio de acceso a {@link Oficina}.
	 */
	@Autowired
	private IOficinaService oficinaService;

	public List<SolicitudIngresoDto> getAllSolicitudes() {

		List<SolicitudIngresoDto> solicitudesDto = null;
		try {

			SolicitudIngresoDao sdao = this.getDaoFactory().newDao(SolicitudIngresoDao.class);
			List<SolicitudIngreso> solicitudes = sdao.getAll(SolicitudIngreso.class);
			solicitudesDto = this.getLisDTO(solicitudes);

		} catch (DaoException e) {
			e.printStackTrace();
		}

		return solicitudesDto;
	}

	public List<SolicitudIngresoDto> getSolicitudesPorFechaSolicitud(Date fechaSolicitud) {
		List<SolicitudIngresoDto> solicitudesDto = null;
		try {
			SolicitudIngresoDao sdao = this.getDaoFactory().newDao(SolicitudIngresoDao.class);

			List<SolicitudIngreso> solicitudes = sdao.getSolicitudesPorFechaSolicitud(fechaSolicitud);

			solicitudesDto = this.getLisDTO(solicitudes);

		} catch (DaoException e) {
			e.printStackTrace();
		}

		return solicitudesDto;
	}

	private List<SolicitudIngresoDto> getLisDTO(List<SolicitudIngreso> solicitudes) {

		List<SolicitudIngresoDto> solicitudesDto = null;
		if (!solicitudes.isEmpty()) {
			solicitudesDto = new Vector<SolicitudIngresoDto>();
			for (SolicitudIngreso solicitudIngreso : solicitudes) {
				SolicitudIngresoDto solicitudDto = this.crearDTO(solicitudIngreso);
				solicitudesDto.add(solicitudDto);
			}
		}

		return solicitudesDto;
	}

	private SolicitudIngresoDto crearDTO(SolicitudIngreso solicitudIngreso) {

		SolicitudIngresoDto solicitudDTO = new SolicitudIngresoDto();

		solicitudDTO.setIdSolicitud(solicitudIngreso.getId());
		solicitudDTO.setSolicitudCandidatos(null);

		/* Se completa la relacion Solicitudes-Entrevistas */
		List<EntrevistaDto> entrevistasDto = new ArrayList<EntrevistaDto>();
		for (Entrevista entrevista : solicitudIngreso.getAllEntrevistas()) {
			entrevistasDto.add(this.entrevistaService.getEntrevistaDto(entrevista));
		}
		solicitudDTO.setEntrevistas(entrevistasDto);

		solicitudDTO.setCantidadVacantes(solicitudIngreso.getCantidadVacantes());

		solicitudDTO.setEstadoSolicitudId(solicitudIngreso.getEstadoSolicitud().getId());
		solicitudDTO.setEstadoSolicitudDescripcion(solicitudIngreso.getEstadoSolicitud().toString());

		solicitudDTO.setGerenteSolicitante(solicitudIngreso.getGerenteSolicitante());
		solicitudDTO.setNecesidadIngresoCode(solicitudIngreso.getNecesidadIngreso().getCode());
		solicitudDTO.setNecesidadIngresoDescripcion(solicitudIngreso.getNecesidadIngreso().getDescripcion());
		solicitudDTO.setObservaciones(solicitudIngreso.getObservaciones());
		solicitudDTO.setOficinaCode(solicitudIngreso.getOficina().getCodigo());
		solicitudDTO.setOficinaDescripcion(solicitudIngreso.getOficina().getDescripcion());
		solicitudDTO.setOtraNecesidadIngreso(solicitudIngreso.getOtraNecesidadIngreso());
		solicitudDTO.setProyectoAsignado(solicitudIngreso.getProyectoAsignado());
		solicitudDTO.setSuperiorDirecto(solicitudIngreso.getSuperiorDirecto());
		solicitudDTO.setJustificacion(solicitudIngreso.getJustificacion());
		solicitudDTO.setFechaEsperadaIncorporacion(ConexiaDateUtil.getDateFormateada(solicitudIngreso.getFechaEsperadaIncorporacion()));
		if (solicitudIngreso.getFechaInicioBusqueda() != null) {
			solicitudDTO.setFechaInicioBusqueda(ConexiaDateUtil.getDateFormateada(solicitudIngreso.getFechaInicioBusqueda()));
		}
		solicitudDTO.setFechaSolicitud(ConexiaDateUtil.getDateFormateada(solicitudIngreso.getFechaSolicitud()));

		solicitudDTO.setPerfilId(solicitudIngreso.getPerfil().getId());
		solicitudDTO.setPerfilNombre(solicitudIngreso.getPerfil().getNombre());

		return solicitudDTO;
	}

	/**
	 * Guarda una nueva solicitud de ingreso en la base de datos.
	 * 
	 * @param solicitudIngresoDto
	 *            el dto con los datos de la solicitud a guardar.
	 * 
	 * @throws ServiceException
	 *             En caso de error guardando la solicitud de ingreso.
	 */
	public void saveSolicitudIngreso(SolicitudIngresoDto solicitudIngresoDto) throws ServiceException {

		try {

			SolicitudIngreso nuevaSolicitud = new SolicitudIngreso();
			nuevaSolicitud.setCantidadVacantes(solicitudIngresoDto.getCantidadVacantes());
			nuevaSolicitud.setEstadoSolicitud(EstadoSolicitud.ABIERTA);

			SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy");

			nuevaSolicitud
					.setFechaEsperadaIncorporacion(sdf.parse(solicitudIngresoDto.getFechaEsperadaIncorporacion()));
			nuevaSolicitud.setFechaInicioBusqueda(null);

			Calendar calendario = GregorianCalendar.getInstance();
			Date fecha = calendario.getTime();
			nuevaSolicitud.setFechaSolicitud(sdf.parse(sdf.format(fecha)));

			nuevaSolicitud.setGerenteSolicitante(solicitudIngresoDto.getGerenteSolicitante());
			nuevaSolicitud.setObservaciones(solicitudIngresoDto.getObservaciones());

			nuevaSolicitud.setNecesidadIngresoId(NecesidadIngreso.fromCode(solicitudIngresoDto
					.getNecesidadIngresoCode()));
			if (NecesidadIngreso.OTROS.equals(NecesidadIngreso.fromCode(solicitudIngresoDto.getNecesidadIngresoCode()))) {
				nuevaSolicitud.setOtraNecesidadIngreso(solicitudIngresoDto.getOtraNecesidadIngreso());
			}

			Perfil perfilSeleccionado = this.perfilService.getPerfilById(solicitudIngresoDto.getPerfilId());
			nuevaSolicitud.setPerfil(perfilSeleccionado);

			nuevaSolicitud.setProyectoAsignado(solicitudIngresoDto.getProyectoAsignado());
			nuevaSolicitud.setSuperiorDirecto(solicitudIngresoDto.getSuperiorDirecto());

			nuevaSolicitud.setOficina(this.oficinaService.getOficinaPorCodigo(solicitudIngresoDto.getOficinaCode()));

			SolicitudIngresoDao dao = this.getDaoFactory().newDao(SolicitudIngresoDao.class);
			dao.saveOrUpdate(nuevaSolicitud);

		} catch (Exception e) {
			throw new ServiceException(e);
		}

	}

	/**
	 * Retorna la solicitud de ingreso con el idSolicitud pasado.
	 * 
	 * @param idSolicitud
	 *            el id de la solicitud buscada.
	 * 
	 * @throws ServiceException
	 *             En caso de error obteniendo la solicitud de ingreso.
	 */
	public SolicitudIngresoDto getSolicitudDtoPorId(Long idSolicitud) throws ServiceException {

		try {

			SolicitudIngresoDao dao = this.getDaoFactory().newDao(SolicitudIngresoDao.class);
			SolicitudIngreso solicitudIngreso = dao.getSolicitudPorId(idSolicitud);

			return this.crearDTO(solicitudIngreso);

		} catch (DaoException e) {
			throw new ServiceException(e);
		}

	}

	/**
	 * Actualiza el estado de la solicitud de ingreso a cerrada.
	 * 
	 * @param idSolicitud
	 *            el id de la solicitud a actualizar.
	 * @param justificacion
	 *            de porque se cerro la solicitud.
	 * 
	 * @throws ServiceException
	 *             En caso de error actualzando la solicitud de ingreso.
	 */
	public void cerrarSolicitudIngreso(Long idSolicitud, String justificacion) throws ServiceException {

		try {

			SolicitudIngresoDao dao = this.getDaoFactory().newDao(SolicitudIngresoDao.class);
			SolicitudIngreso solicitudIngreso = dao.getSolicitudPorId(idSolicitud);

			if (solicitudIngreso != null) {
				solicitudIngreso.setEstadoSolicitud(EstadoSolicitud.CERRADA);
				solicitudIngreso.setJustificacion(justificacion);
			}

			dao.saveOrUpdate(solicitudIngreso);

		} catch (DaoException e) {
			throw new ServiceException(e);
		}

	}

	/**
	 * Actualiza el estado de la solicitud de ingreso a rechazada.
	 * 
	 * @param idSolicitud
	 *            el id de la solicitud a actualizar.
	 * @param justificacion
	 *            de porque se rechazo la solicitud.
	 * 
	 * @throws ServiceException
	 *             En caso de error actualzando la solicitud de ingreso.
	 */
	public void rechazarSolicitudIngreso(Long idSolicitud, String justificacion) throws ServiceException {
		try {

			SolicitudIngresoDao dao = this.getDaoFactory().newDao(SolicitudIngresoDao.class);
			SolicitudIngreso solicitudIngreso = dao.getSolicitudPorId(idSolicitud);

			if (solicitudIngreso != null) {
				solicitudIngreso.setEstadoSolicitud(EstadoSolicitud.RECHAZADA);
				solicitudIngreso.setJustificacion(justificacion);
			}

			dao.saveOrUpdate(solicitudIngreso);

		} catch (DaoException e) {
			throw new ServiceException(e);
		}
	}

	/**
	 * Actualiza el estado de la solicitud de ingreso a aprobado.
	 * 
	 * @param idSolicitud
	 *            el id de la solicitud a actualizar.
	 * 
	 * @throws ServiceException
	 *             En caso de error actualzando la solicitud de ingreso.
	 */
	public void aprobarSolicitudIngreso(Long idSolicitud) throws ServiceException {
		try {

			SolicitudIngresoDao dao = this.getDaoFactory().newDao(SolicitudIngresoDao.class);
			SolicitudIngreso solicitudIngreso = dao.getSolicitudPorId(idSolicitud);

			if (solicitudIngreso != null) {
				solicitudIngreso.setEstadoSolicitud(EstadoSolicitud.APROBADA);
			}

			dao.saveOrUpdate(solicitudIngreso);

		} catch (DaoException e) {
			throw new ServiceException(e);
		}
	}

	public List<SolicitudIngresoDto> getAllSolicitudesByTipoUsuario(TipoUsuario tipoUsuario) throws ServiceException {
		
		List<SolicitudIngresoDto> solicitudesDto = null;
		try {

			SolicitudIngresoDao sdao = this.getDaoFactory().newDao(SolicitudIngresoDao.class);

			if(TipoUsuario.AUDITOR.equals(tipoUsuario)){
				
				List<SolicitudIngreso> solicitudes = sdao.getAllForAuditor();
				solicitudesDto = this.getLisDTO(solicitudes);
				
			} else if(TipoUsuario.ANALISTA_RRHH.equals(tipoUsuario)){
				
				List<SolicitudIngreso> solicitudes = sdao.getAllForAnalista();
				solicitudesDto = this.getLisDTO(solicitudes);
				
			} else if(TipoUsuario.ADMINISTRADOR.equals(tipoUsuario)){
				List<SolicitudIngreso> solicitudes = sdao.getAll(SolicitudIngreso.class);
				solicitudesDto = this.getLisDTO(solicitudes);
			
			} else if(TipoUsuario.COLABORADOR.equals(tipoUsuario)){
				List<SolicitudIngreso> solicitudes = sdao.getAllForColaborador();
				solicitudesDto = this.getLisDTO(solicitudes);
			}
		

		} catch (DaoException e) {

			e.printStackTrace();
		}

		return solicitudesDto;
	}

	public List<SolicitudIngresoDto> getAllSolicitudesAprobadas() throws ServiceException {
		
		List<SolicitudIngresoDto> solicitudesDto = null;
		try {

			SolicitudIngresoDao sdao = this.getDaoFactory().newDao(SolicitudIngresoDao.class);
			List<SolicitudIngreso> solicitudes = sdao.getAllSolicitudesAprobadas();
			solicitudesDto = this.getLisDTO(solicitudes);

		} catch (DaoException e) {

			e.printStackTrace();
		}

		return solicitudesDto;
	}

	public SolicitudIngreso getSolicitudPorId(Long idSolicitud) {
		try {

			SolicitudIngresoDao sdao = this.getDaoFactory().newDao(SolicitudIngresoDao.class);
			return sdao.getSolicitudPorId(idSolicitud);

		} catch (DaoException e) {
			e.printStackTrace();
		}
		
		return null;
	}
}
